<!DOCTYPE html>
<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#determining-registration">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./resources/utils.js"></script>
<div id=outer>
  <div id=div></div>
</div>
<script>

test_with_at_property({
  syntax: '"<length>"',
  inherits: false,
  initialValue: '1px'
}, (name) => {
  assert_equals(getComputedStyle(div).getPropertyValue(name), '1px');
}, '@property determines the registration when uncontested');

test_with_at_property({
  syntax: '"<length>"',
  inherits: false,
  initialValue: '2px'
}, (name) => {
  CSS.registerProperty({
    name: name,
    syntax: '<color>',
    inherits: false,
    initialValue: 'green'
  });
  assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(0, 128, 0)');
}, 'CSS.registerProperty wins over @property');

test_with_at_property({
  syntax: '"<length>"',
  inherits: false,
  initialValue: '3px'
}, (name1) => {
  with_at_property({
    name: name1,
    syntax: '"<integer>"',
    inherits: false,
    initialValue: '6'
  }, (name2) => {
    assert_equals(name1, name2);
    assert_equals(getComputedStyle(div).getPropertyValue(name2), '6');
  });
}, '@property later in document order wins');

test(() => {
  let name = generate_name();

  with_style_node(`
    @property ${name} {
      syntax: "<length>";
      inherits: false;
      initial-value: 4px;
    }

    @property ${name} {
      syntax: "<color>";
      inherits: false;
      initial-value: red;
    }
  `, () => {
    assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(255, 0, 0)');
  });
}, '@property later in stylesheet wins');

test(() => {
  let name = generate_name();
  CSS.registerProperty({
    name: name,
    syntax: '<color>',
    inherits: false,
    initialValue: 'green'
  });
  assert_equals(getComputedStyle(div).getPropertyValue(name), 'rgb(0, 128, 0)');
}, 'CSS.registerProperty determines the registration when uncontested');

test(() => {
  let name = generate_name();

  // ${name} is initially not registered, hence has no initial value.
  assert_equals(getComputedStyle(div).getPropertyValue(name), '');

  with_at_property({
    name: name,
    syntax: '"<length>"',
    inherits: false,
    initialValue: '10px'
  }, () => {
    assert_equals(getComputedStyle(div).getPropertyValue(name), '10px');
  });

  // When the style node is removed, ${name} should be unregistered again.
  assert_equals(getComputedStyle(div).getPropertyValue(name), '');
}, '@property registrations are cleared when rule removed');

test(() => {
  let name = generate_name();

  with_style_node(`div { ${name}: calc(1px + 1px); }`, () => {
    // ${name} should be a token sequence at this point.
    assert_equals(getComputedStyle(div).getPropertyValue(name), ' calc(1px + 1px)');

    with_at_property({
      name: name,
      syntax: '"<length>"',
      inherits: false,
      initialValue: '0px'
    }, () => {
      // ${name} is now a <length>, hence the calc() should be simplified.
      assert_equals(getComputedStyle(div).getPropertyValue(name), '2px');
    });

    // ${name} should be a token sequence again.
    assert_equals(getComputedStyle(div).getPropertyValue(name), ' calc(1px + 1px)');
  });
}, 'Computed value becomes token sequence when @property is removed');

test(() => {
  let name = generate_name();

  with_style_node(`#outer { ${name}: 10px; }`, () => {
    assert_equals(getComputedStyle(div).getPropertyValue(name), ' 10px');

    with_at_property({
      name: name,
      syntax: '"<length>"',
      inherits: false,
      initialValue: '0px'
    }, () => {
      // ${name} is no longer inherited
      assert_equals(getComputedStyle(div).getPropertyValue(name), '0px');
    });

    assert_equals(getComputedStyle(div).getPropertyValue(name), ' 10px');
  });
}, 'Inherited status is reflected in computed styles when @property is removed');

test(() => {
  let name = generate_name();

  with_style_node(`
    @property ${name} {
      syntax: "<length>";
      inherits: false;
      initial-value: 1px;
    }

    @property ${name} {
      inherits: false;
      initial-value: green;
    }
  `, () => {
    assert_equals(getComputedStyle(div).getPropertyValue(name), '1px');
  });
}, 'Invalid @property rule (missing syntax) does not overwrite previous valid rule');

test(() => {
  let name = generate_name();

  with_style_node(`
    @property ${name} {
      syntax: "<length>";
      inherits: false;
      initial-value: 1px;
    }

    @property ${name} {
      syntax: "<color>";
      initial-value: green;
    }
  `, () => {
    assert_equals(getComputedStyle(div).getPropertyValue(name), '1px');
  });
}, 'Invalid @property rule (missing inherits descriptor) does not overwrite previous valid rule');

test(() => {
  let name = generate_name();

  with_style_node(`
    @property ${name} {
      syntax: "<length>";
      inherits: false;
      initial-value: 1px;
    }

    @property ${name} {
      syntax: "<color>";
      inherits: false;
    }
  `, () => {
    assert_equals(getComputedStyle(div).getPropertyValue(name), '1px');
  });
}, 'Invalid @property rule (missing initial-value) does not overwrite previous valid rule');

test(() => {
  let name = generate_name();

  with_style_node(`
    @property ${name} {
      syntax: "<color>";
      inherits: false;
    }

    @property ${name} {
      syntax: "<length>";
      inherits: false;
      initial-value: 1px;
    }
  `, () => {
    assert_equals(getComputedStyle(div).getPropertyValue(name), '1px');
  });
}, 'Previous invalid rule does not prevent valid rule from causing registration');

test(() => {
  let name = generate_name();

  with_style_node(`
    @property ${name} {
      syntax: "<length>";
      inherits: false;
      initial-value: 1px;
      quite-unknown: 200;
    }
  `, () => {
    assert_equals(getComputedStyle(div).getPropertyValue(name), '1px');
  });
}, 'Unknown descriptors are ignored and do not invalidate rule');

</script>
